﻿#include "stdafx.h"
#include "skinbitmap.h"
const int HIMETRIC_INCH	= 2540;

void RGBtoHLS(COLORREF color,double *H, double *L, double *S)
{
	double		r = (double)GetRValue(color)/ 255.0 ;
	double		g = (double)GetGValue(color) / 255.0 ;
	double		b = (double)GetBValue(color) / 255.0 ;
	double		cmax = max (r, max (g, b)) ;
	double		cmin = min (r, min (g, b)) ;
	*L = (cmax+cmin) / 2.0 ;
	if (cmax == cmin)
	{
		*S = 0 ;
		*H = 0 ;
	}
	else
	{
		if (*L < 0.5) 
			*S = (cmax-cmin) / (cmax+cmin) ;
		else
			*S = (cmax-cmin) / (2.0-cmax-cmin) ;

		double     delta = cmax - cmin ;
		if (delta == 0.0)
			delta = 1.0 ;

		if (r == cmax)
			*H = (g-b) / delta ;
		else
			if (g == cmax)
				*H = 2.0 + (b-r) / delta ;
			else
				*H = 4.0 + (r-g) / delta ;
		*H /= 6.0 ;
		if (*H < 0.0)
			*H += 1 ;
	}
}
double  __F_HLS_Value (const double &m1, double const &m2, double h)
{
	if (h < 0)
		h += 1.0 ;
	if (h > 1)
		h -= 1.0 ;
	if (6.0*h < 1)
		return (m1+(m2-m1)*h*6.0) ;
	if (2.0*h < 1)
		return m2 ;
	if (3.0*h < 2.0)
		return (m1+(m2-m1)*((2.0/3.0)-h)*6.0) ;
	return m1 ;
}
COLORREF HLStoRGB(const double& H, const double& L, const double& S)
{
	double		r, g, b ;
	if (S == 0)
	{
		r = g = b = L ;
	}
	else 
	{
		double		m1, m2 ;
		if (L <= 0.5)
			m2 = L * (1.0+S) ;
		else
			m2 = L + S - L*S ;
		m1 = 2.0*L - m2 ;
		r = __F_HLS_Value (m1, m2, H+1.0/3.0) ;
		g = __F_HLS_Value (m1, m2, H) ;
		b = __F_HLS_Value (m1, m2, H-1.0/3.0) ;
	}
	BYTE red,green,blue ;
	red   = max (min ((int)(r*255), 0xFF), 0) ;
	green = max (min ((int)(g*255), 0xFF), 0) ;
	blue  = max (min ((int)(b*255), 0xFF), 0) ;
	return RGB(red,green,blue) ;
}

/******************************************
* 函数名 : CSkinBitmap
* 功能 : 构造函数
*******************************************/
CSkinBitmap::CSkinBitmap(void)
:m_lpBuffer(NULL)
,m_nSize(0)
,m_strName(_T(""))
{
}
/******************************************
* 函数名 : ~CSkinBitmap
* 功能 : 析构函数
*******************************************/
CSkinBitmap::~CSkinBitmap(void)
{
	if(m_lpBuffer)
		delete []m_lpBuffer;
	m_lpBuffer = NULL;
}
COLORREF CSkinBitmap::GetTransparentColor() const
{
	CBitmap* pBitmap = (CBitmap*)this;
	if (pBitmap != NULL)
	{
		CCompatibleDC dc(NULL, pBitmap);
		return dc.GetPixel(0,0);
	}
	return (COLORREF)-1;
}
/******************************************
* 函数名 : LoadImage
* 功能 : 从资源文件中载入位图
*******************************************/
BOOL CSkinBitmap::LoadImage(UINT uIDRes, LPCTSTR szResourceType, HMODULE hInst, COLORREF crBack)
{
	ASSERT(m_hObject == NULL);      // only attach once, detach on destroy
	if (m_hObject != NULL)
		return FALSE;
	if(m_lpBuffer)
		delete []m_lpBuffer;
	BOOL bResult = FALSE;
	// first call is to get buffer size
	if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, 0, m_nSize))
	{
		if (m_nSize > 0)
		{
			m_lpBuffer = new BYTE[m_nSize];

			// this loads it
			if (GetResource(MAKEINTRESOURCE(uIDRes), szResourceType, hInst, m_lpBuffer, m_nSize))
			{
				IPicture* pPicture = LoadFromBuffer(m_lpBuffer, m_nSize);

				if (pPicture)
				{
					bResult = Attach(pPicture, crBack);
					pPicture->Release();
				}
			}
		}
	}

	return bResult;
}
/******************************************
* 函数名 : LoadImage
* 功能 : 从文件中载入位图
*******************************************/
BOOL CSkinBitmap::LoadImage(LPCTSTR szImagePath, COLORREF crBack)
{
	ASSERT(m_hObject == NULL);      // only attach once, detach on destroy

	if (m_hObject != NULL)
		return FALSE;
	if(m_lpBuffer)
		delete []m_lpBuffer;
	BOOL bResult = FALSE;
	CFile			cFile;
	CFileException	e;

	if (cFile.Open(szImagePath, CFile::modeRead | CFile::typeBinary, &e))
	{
		m_nSize= cFile.GetLength();

		m_lpBuffer = new BYTE[m_nSize];

		if (cFile.Read(m_lpBuffer, m_nSize) > 0)
		{
			IPicture* pPicture = LoadFromBuffer(m_lpBuffer, m_nSize);

			if (pPicture)
			{
				bResult = Attach(pPicture, crBack);
				pPicture->Release();
			}
		}
	}
	return bResult;
}

/******************************************
* 函数名 : LoadImage
* 功能 : 从内存BUUFER中加载位图
*******************************************/
BOOL CSkinBitmap::LoadImage(LPBYTE lpBuffer,int nSize, COLORREF crBack)
{
	ASSERT(m_hObject == NULL);      // only attach once, detach on destroy

	if (m_hObject != NULL)
		return FALSE;

	BOOL bResult = FALSE;
	
	if (lpBuffer)
	{
		IPicture* pPicture = LoadFromBuffer(lpBuffer, nSize);
		if (pPicture)
		{
			bResult = Attach(pPicture, crBack);
			pPicture->Release();
		}
	}
	return bResult;
}
/******************************************
* 函数名 : LoadFromBuffer
* 功能 : 从内存重载入位图
*******************************************/
IPicture* CSkinBitmap::LoadFromBuffer(BYTE* pBuff, int nSize)
{
	bool bResult = false;

	HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, nSize);
	void* pData = GlobalLock(hGlobal);
	memcpy(pData, pBuff, nSize);
	GlobalUnlock(hGlobal);

	IStream* pStream = NULL;
	IPicture* pPicture = NULL;
	if (CreateStreamOnHGlobal(hGlobal, TRUE, &pStream) == S_OK)
	{
		HRESULT hr = OleLoadPicture(pStream, nSize, FALSE, IID_IPicture, (LPVOID *)&pPicture);
		pStream->Release();
	}
	return pPicture; // caller releases
}
BOOL CSkinBitmap::Save(CFile &file)
{
	char name[256];
	strcpy(name,m_strName);
	file.Write(name,256);
	file.Write(&m_nSize,sizeof(m_nSize));
	file.Write(m_lpBuffer,m_nSize);
	return TRUE;
}
BOOL CSkinBitmap::Load(CFile &file)
{
	char name[256];
	file.Read(name,256);
	m_strName = name;
	file.Read(&m_nSize,sizeof(m_nSize));
	if(m_nSize)
	{
		m_lpBuffer = new BYTE[m_nSize];
		file.Read(m_lpBuffer,m_nSize);
		if(m_lpBuffer)
			LoadImage(m_lpBuffer,m_nSize);
	}
	return TRUE;
}
void CSkinBitmap::Serialize(CArchive& ar)
{
	if(ar.IsStoring())
	{
		char name[256];
		strcpy(name,m_strName);
		ar.Write(name,256);
		ar.Write(&m_nSize,sizeof(m_nSize));
		ar.Write(m_lpBuffer,m_nSize);
	}
	else
	{
		char name[256];
		//	strcpy(name,m_strName);
		ar.Read(name,256);
		m_strName = name;
		ar.Read(&m_nSize,sizeof(m_nSize));
		if(m_nSize)
		{
			m_lpBuffer = new BYTE[m_nSize];
			ar.Read(m_lpBuffer,m_nSize);
			if(m_lpBuffer)
				LoadImage(m_lpBuffer,m_nSize);
		}
	}
}
/******************************************
* 函数名 : GetResource
* 功能 : 从资源中获取位图buffer
*******************************************/
BOOL CSkinBitmap::GetResource(LPCTSTR lpName, LPCTSTR lpType, HMODULE hInst, void* pResource, int& nBufSize)
{ 
	HRSRC		hResInfo;
	HANDLE		hRes;
	LPSTR		lpRes	= NULL; 
	int			nLen	= 0;
	bool		bResult	= FALSE;
	// Find the resource
	hResInfo = FindResource(hInst, lpName, lpType);

	if (hResInfo == NULL) 
		return false;

	// Load the resource
	hRes = LoadResource(hInst, hResInfo);

	if (hRes == NULL) 
		return false;

	// Lock the resource
	lpRes = (char*)LockResource(hRes);

	if (lpRes != NULL)
	{ 
		if (pResource == NULL)
		{
			nBufSize = SizeofResource(hInst, hResInfo);
			bResult = true;
		}
		else
		{
			if (nBufSize >= (int)SizeofResource(hInst, hResInfo))
			{
				memcpy(pResource, lpRes, nBufSize);
				bResult = true;
			}
		} 

		UnlockResource(hRes);  
	}

	// Free the resource
	FreeResource(hRes);

	return bResult;
}
/******************************************
* 函数名 : Attach
* 功能	 : 关联位图	 
*******************************************/
BOOL CSkinBitmap::Attach(IPicture* pPicture, COLORREF crBack)
{
	ASSERT(m_hObject == NULL);      // only attach once, detach on destroy
	if (m_hObject != NULL)
		return FALSE;
	ASSERT(pPicture);
	if (!pPicture)
		return FALSE;
	BOOL bResult = FALSE;
	CDC dcMem;
	CDC* pDC = CWnd::GetDesktopWindow()->GetDC();
	if (dcMem.CreateCompatibleDC(pDC))
	{
		long hmWidth;
		long hmHeight;
		pPicture->get_Width(&hmWidth);
		pPicture->get_Height(&hmHeight);

		int nWidth	= MulDiv(hmWidth,	pDC->GetDeviceCaps(LOGPIXELSX), HIMETRIC_INCH);
		int nHeight	= MulDiv(hmHeight,	pDC->GetDeviceCaps(LOGPIXELSY), HIMETRIC_INCH);

		CBitmap bmMem;

		if (bmMem.CreateCompatibleBitmap(pDC, nWidth, nHeight))
		{
			CBitmap* pOldBM = dcMem.SelectObject(&bmMem);
			if (crBack != -1)
				dcMem.FillSolidRect(0, 0, nWidth, nHeight, crBack);

			HRESULT hr = pPicture->Render(dcMem, 0, 0, nWidth, nHeight, 0, hmHeight, hmWidth, -hmHeight, NULL);
			dcMem.SelectObject(pOldBM);
			if (hr == S_OK)
				bResult = CBitmap::Attach(bmMem.Detach());
		}
	}
	CWnd::GetDesktopWindow()->ReleaseDC(pDC);
	return bResult;
}
/******************************************
* 函数名 : TransparentDraw
* 功能	 : 透明绘制位图 
*******************************************/
BOOL CSkinBitmap::TransparentDraw( CDC *pDC, COLORREF crColour, LPCRECT lpRectDst, 
									   LPCRECT lpRectSrc, int mode)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;			// 目标位置数据
	CRect rectSrc;			// 源位置数据

	if (lpRectDst)
		rectDst = *lpRectDst;
	else
		rectDst.SetRect(0,0,GetWidth(),GetHeight());
	if (lpRectSrc)
		rectSrc = *lpRectSrc;
	else
		rectSrc.SetRect(0,0,GetWidth(),GetHeight());
	COLORREF crOldBack;
	COLORREF crOldText;

	if (mode==0)
	{	// 去除指定的颜色
		crOldBack = pDC->SetBkColor(RGB(255,255,255));
		crOldText = pDC->SetTextColor(RGB(0,0,0));
	}
	else
	{	// 保留指定的颜色
		crOldBack = pDC->SetBkColor(RGB(0,0,0));
		crOldText = pDC->SetTextColor(RGB(255,255,255));
	}

	CDC dcImage, dcTrans;

	// 创建内存设备描述表
	dcImage.CreateCompatibleDC(pDC);
	dcTrans.CreateCompatibleDC(pDC);

	// 选择原始图像到DC中
	CBitmap* pOldBitmapImage = dcImage.SelectObject(this);
	// 创建掩码位图
	CBitmap bitmapTrans;
	int nWidth = rectDst.Width();
	int nHeight = rectDst.Height();
	bitmapTrans.CreateBitmap(nWidth, nHeight, 1, 1, NULL);

	// 选择掩码位图到DC中
	CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans);
	// 创建掩码图像（基于指定的颜色）
	dcImage.SetBkColor(crColour);
	dcTrans.StretchBlt(0,0, nWidth, nHeight, &dcImage, rectSrc.left, rectSrc.top,rectSrc.Width(),rectSrc.Height(), SRCCOPY);

	/* 设置目标DC的拉伸模式为STRETCH_DELETESCANS，也就是不显示拉伸掉的图像 */
	int srlold = pDC->SetStretchBltMode(STRETCH_DELETESCANS);

	// 显示位图
	pDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(),
		&dcImage,rectSrc.left,rectSrc.top,rectSrc.Width(),rectSrc.Height(),SRCINVERT);
	pDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(),
		&dcTrans,0,0,nWidth,nHeight,SRCAND);
	pDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(),
		&dcImage,rectSrc.left,rectSrc.top,rectSrc.Width(),rectSrc.Height(),SRCINVERT);

	// 恢复设备描述表原来的设置
	pDC->SetStretchBltMode(srlold);
	// 恢复设置
	dcImage.SelectObject(pOldBitmapImage);
	dcTrans.SelectObject(pOldBitmapTrans);
	pDC->SetBkColor(crOldBack);
	pDC->SetTextColor(crOldText);

	return TRUE;
}
/******************************************
* 函数名 : Draw
* 功能	 : 设备描述表之间绘制 
*******************************************/
BOOL CSkinBitmap::Draw(CDC *pDstDC,CDC *pSrcDC,LPCRECT lpRectDst,LPCRECT lpRectSrc )
{
	if(pDstDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;			// 目标位置数据
	CRect rectSrc;			// 源位置数据

	if (lpRectDst)
		rectDst = *lpRectDst;
	if (lpRectSrc)
		rectSrc = *lpRectSrc;

	if(lpRectSrc)
	{
		/* 设置目标DC的拉伸模式为STRETCH_DELETESCANS，也就是不显示拉伸掉的图像 */
		int srlold = pDstDC->SetStretchBltMode(STRETCH_DELETESCANS);
		pDstDC->StretchBlt(rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(),
			pSrcDC, rectSrc.left, rectSrc.top ,rectSrc.Width(),rectSrc.Height(),SRCCOPY );
		pDstDC->SetStretchBltMode(srlold);
	}
	else
	{
		pDstDC->BitBlt( rectDst.left,rectDst.top,rectDst.Width(),rectDst.Height(),
			pSrcDC, 0, 0 ,SRCCOPY );
	}
	return TRUE;
}
/******************************************
* 函数名 : Draw
* 功能	 : 位图绘制函数 
*******************************************/
BOOL CSkinBitmap::Draw(CDC *pDC, LPCRECT lpRectDst,LPCRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CDC dc;
	dc.CreateCompatibleDC( pDC );
	CBitmap * bmp = dc.SelectObject( this );
	Draw(pDC,&dc,lpRectDst,lpRectSrc);
	dc.SelectObject( bmp );		
	return TRUE;
}
/******************************************
* 函数名 : TitleDraw
* 功能	 : 填充位图绘制函数 
*******************************************/
BOOL CSkinBitmap::TitleDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc )
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	//矩形坐标规范画
	rectDst.NormalizeRect();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	CRect rectTemp;
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	CDC dc;
	dc.CreateCompatibleDC( pDC );
	CBitmap * bmp = dc.SelectObject( this );
	for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight)
	{
		for(int x = rectDst.left ; x < rectDst.right ; x += nWidth)
		{
			rectTemp.SetRect(x,y,x+nWidth,y+nHeight);
			Draw(pDC,&dc,&rectTemp,lpRectSrc);
		}
	}
	dc.SelectObject(bmp);
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : CenterDraw
* 功能	 : 中央位图绘制函数 
*******************************************/
BOOL CSkinBitmap::CenterDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	//矩形坐标规范化
	rectDst.NormalizeRect();

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	//计算源区域的宽度和高度
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	// 取指定矩形的中点坐标
	CPoint ptCeneter = rectDst.CenterPoint();
	CRect rectTemp(ptCeneter.x - nWidth/2, ptCeneter.y - nHeight/2, 
					ptCeneter.x - nWidth/2, ptCeneter.y + nHeight/2);
	CDC dc;
	dc.CreateCompatibleDC( pDC );
	CBitmap * bmp = dc.SelectObject( this );
	Draw(pDC,&dc,&rectTemp,lpRectSrc);
	dc.SelectObject(bmp);
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : WidthStretchDraw
* 功能	 : 宽度伸展函数 
*******************************************/
BOOL CSkinBitmap::WidthStretchDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc )
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	//矩形坐标规范化
	rectDst.NormalizeRect();

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	CRect rectTemp;
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	CDC dc;
	dc.CreateCompatibleDC( pDC );
	CBitmap * bmp = dc.SelectObject( this );
	for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight)
	{
		rectTemp.SetRect(rectDst.left, y,rectDst.right, y + nHeight);
		Draw(pDC,&dc,&rectTemp,lpRectSrc);
	}
	dc.SelectObject(bmp);
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : HeightStretchDraw
* 功能	 : 高度伸展绘制函数 
*******************************************/
BOOL CSkinBitmap::HeightStretchDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	//矩形坐标规范化
	rectDst.NormalizeRect();

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	CRect rectTemp;
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	CDC dc;
	dc.CreateCompatibleDC( pDC );
	CBitmap * bmp = dc.SelectObject( this );
	for(int x = rectDst.left ; x < rectDst.right ; x += nWidth)
	{
		rectTemp.SetRect(x, rectDst.top,x + nWidth, rectDst.bottom);
		Draw(pDC,&dc,&rectTemp,lpRectSrc);
	}
	dc.SelectObject(bmp);
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : HeightStretchDraw
* 功能	 : 伸展绘制函数 
*******************************************/
BOOL CSkinBitmap::AllStretchDraw(CDC *pDC, LPRECT lpRectDst,LPRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	else
		rectSrc.SetRect(0, 0, GetWidth(), GetHeight());
	//矩形坐标规范化
	rectDst.NormalizeRect();
	CDC dc;
	dc.CreateCompatibleDC( pDC );
	CBitmap * bmp = dc.SelectObject( this );
	Draw(pDC,&dc,&rectDst,&rectSrc);
	dc.SelectObject(bmp);
	return TRUE;
}
/******************************************
* 函数名 : TitleTransDraw
* 功能	 : 透明填充绘制函数 
*******************************************/
BOOL CSkinBitmap::TitleTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, 
					LPRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	//矩形坐标规范画
	rectDst.NormalizeRect();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	CRect rectTemp;
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight)
	{
		for(int x = rectDst.left ; x < rectDst.right ; x += nWidth)
		{
			rectTemp.SetRect(x,y,x+nWidth,y+nHeight);
			TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc);
		}
	}
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : CenterTransDraw
* 功能	 : 透明中央绘制函数 
*******************************************/
BOOL CSkinBitmap::CenterTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, 
					 LPRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	//矩形坐标规范化
	rectDst.NormalizeRect();
	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	//计算源区域的宽度和高度
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	// 取指定矩形的中点坐标
	CPoint ptCeneter = rectDst.CenterPoint();
	CRect rectTemp(ptCeneter.x - nWidth/2, ptCeneter.y - nHeight/2, 
		ptCeneter.x - nWidth/2, ptCeneter.y + nHeight/2);
	TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc);
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : WidthStretchTransDraw
* 功能	 : 透明宽度伸展绘制函数 
*******************************************/
BOOL CSkinBitmap::WidthStretchTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, 
						   LPRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	//矩形坐标规范化
	rectDst.NormalizeRect();

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	CRect rectTemp;
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	for(int y = rectDst.top ; y < rectDst.bottom ; y += nHeight)
	{
		rectTemp.SetRect(rectDst.left, y,rectDst.right, y + nHeight);
		TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc);
	}
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : HeightStretchTransDraw
* 功能	 : 透明高度伸展绘制函数 
*******************************************/
BOOL CSkinBitmap::HeightStretchTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, 
							LPRECT lpRectSrc )
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	//矩形坐标规范化
	rectDst.NormalizeRect();

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);
	CRect rectTemp;
	int nWidth  = 0; 
	int	nHeight = 0;
	if(lpRectSrc)
	{
		nWidth  = rectSrc.Width();
		nHeight = rectSrc.Height();
	}
	else
	{
		nWidth  = GetWidth();
		nHeight = GetHeight();
	}
	for(int x = rectDst.left ; x < rectDst.right ; x += nWidth)
	{
		rectTemp.SetRect(x, rectDst.top,x + nWidth, rectDst.bottom);
		TransparentDraw(pDC,crColour,&rectTemp,lpRectSrc);
	}
	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	return TRUE;
}
/******************************************
* 函数名 : AllStretchTransDraw
* 功能	 : 透明伸展绘制函数 
*******************************************/
BOOL CSkinBitmap::AllStretchTransDraw(CDC *pDC, COLORREF crColour, LPRECT lpRectDst, 
						 LPRECT lpRectSrc)
{
	if(pDC == NULL || lpRectDst == NULL)
		return FALSE;
	CRect rectDst;		// 目标位置数据
	CRect rectSrc;		// 源位置数据
	if(lpRectDst)
		rectDst = *lpRectDst;
	if(lpRectSrc)
		rectSrc = *lpRectSrc;
	else
		rectSrc.SetRect(0, 0, GetWidth(), GetHeight());

	rectDst.NormalizeRect();

	//保存当前设备描述表,因下面对其剪贴区域进行更改
	int savedc = pDC->SaveDC();
	CRgn newrgn;
	//设置需要显示的区域
	newrgn.CreateRectRgnIndirect(&rectDst);
	pDC->SelectClipRgn(&newrgn, RGN_AND);


	TransparentDraw(pDC,crColour,rectDst,rectSrc);

	pDC->RestoreDC(savedc);
	newrgn.CGdiObject::DeleteObject();
	
	return TRUE;
}
/******************************************
* 函数名 : CreateRgnFromFile
* 功能	 : 根据位图创建区域 
*******************************************/
HRGN CSkinBitmap::CreateRgnFromFile( COLORREF color )
{
	HBITMAP hBmp = (HBITMAP)this->GetSafeHandle();

	// get image properties
	BITMAP bmp = { 0 };
	::GetObject( hBmp, sizeof(BITMAP), &bmp );
	// allocate memory for extended image information
	LPBITMAPINFO bi = (LPBITMAPINFO) new BYTE[ sizeof(BITMAPINFO) + 8 ];
	memset( bi, 0, sizeof(BITMAPINFO) + 8 );
	bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	// set window size
	int m_dwWidth	= bmp.bmWidth;		// bitmap width
	int m_dwHeight	= bmp.bmHeight;		// bitmap height
	// create temporary dc
	HDC dc = CreateIC( _TEXT("DISPLAY"),NULL,NULL,NULL );
	// get extended information about image (length, compression, length of color table if exist, ...)
	DWORD res = GetDIBits( dc, hBmp, 0, bmp.bmHeight, 0, bi, DIB_RGB_COLORS );
	// allocate memory for image data (colors)
	LPBYTE pBits = new BYTE[ bi->bmiHeader.biSizeImage + 4 ];
	// allocate memory for color table
	if ( bi->bmiHeader.biBitCount == 8 )
	{
		// actually color table should be appended to this header(BITMAPINFO),
		// so we have to reallocate and copy it
		LPBITMAPINFO old_bi = bi;
		// 255 - because there is one in BITMAPINFOHEADER
		bi = (LPBITMAPINFO)new char[ sizeof(BITMAPINFO) + 255 * sizeof(RGBQUAD) ];
		memcpy( bi, old_bi, sizeof(BITMAPINFO) );
		// release old header
		delete old_bi;
	}
	// get bitmap info header
	BITMAPINFOHEADER& bih = bi->bmiHeader;
	// get color table (for 256 color mode contains 256 entries of RGBQUAD(=DWORD))
	LPDWORD clr_tbl = (LPDWORD)&bi->bmiColors;
	// fill bits buffer
	res = GetDIBits( dc, hBmp, 0, bih.biHeight, pBits, bi, DIB_RGB_COLORS );
	DeleteDC( dc );

	BITMAP bm;
	::GetObject( hBmp, sizeof(BITMAP), &bm );
	// shift bits and byte per pixel (for comparing colors)
	LPBYTE pClr = (LPBYTE)&color;
	// swap red and blue components
	BYTE tmp = pClr[0]; pClr[0] = pClr[2]; pClr[2] = tmp;
	// convert color if curent DC is 16-bit (5:6:5) or 15-bit (5:5:5)
	if ( bih.biBitCount == 16 )
	{
		// for 16 bit
		color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
			((DWORD)(pClr[1] & 0xfc) << 3) |
			((DWORD)(pClr[2] & 0xf8) << 8);
		// for 15 bit
		//		color = ((DWORD)(pClr[0] & 0xf8) >> 3) |
		//				((DWORD)(pClr[1] & 0xf8) << 2) |
		//				((DWORD)(pClr[2] & 0xf8) << 7);
	}

	const DWORD RGNDATAHEADER_SIZE	= sizeof(RGNDATAHEADER);
	const DWORD ADD_RECTS_COUNT		= 40;			// number of rects to be appended
	// to region data buffer

	// BitPerPixel
	BYTE	Bpp = bih.biBitCount >> 3;				// bytes per pixel
	// bytes per line in pBits is DWORD aligned and bmp.bmWidthBytes is WORD aligned
	// so, both of them not
	DWORD m_dwAlignedWidthBytes = (bmp.bmWidthBytes & ~0x3) + (!!(bmp.bmWidthBytes & 0x3) << 2);
	// DIB image is flipped that's why we scan it from the last line
	LPBYTE	pColor = pBits + (bih.biHeight - 1) * m_dwAlignedWidthBytes;
	DWORD	dwLineBackLen = m_dwAlignedWidthBytes + bih.biWidth * Bpp;	// offset of previous scan line
	// (after processing of current)
	DWORD	dwRectsCount = bih.biHeight;			// number of rects in allocated buffer
	INT		i, j;									// current position in mask image
	INT		first = 0;								// left position of current scan line
	// where mask was found
	bool	wasfirst = false;						// set when mask has been found in current scan line
	bool	ismask;									// set when current color is mask color

	// allocate memory for region data
	// region data here is set of regions that are rectangles with height 1 pixel (scan line)
	// that's why first allocation is <bm.biHeight> RECTs - number of scan lines in image
	RGNDATAHEADER* pRgnData = 
		(RGNDATAHEADER*)new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
	// get pointer to RECT table
	LPRECT pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
	// zero region data header memory (header  part only)
	memset( pRgnData, 0, RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) );
	// fill it by default
	pRgnData->dwSize	= RGNDATAHEADER_SIZE;
	pRgnData->iType		= RDH_RECTANGLES;

	for ( i = 0; i < bih.biHeight; i++ )
	{
		for ( j = 0; j < bih.biWidth; j++ )
		{
			// get color
			switch ( bih.biBitCount )
			{
			case 8:
				ismask = (clr_tbl[ *pColor ] != color);
				break;
			case 16:
				ismask = (*(LPWORD)pColor != (WORD)color);
				break;
			case 24:
				ismask = ((*(LPDWORD)pColor & 0x00ffffff) != color);
				break;
			case 32:
				ismask = (*(LPDWORD)pColor != color);
			}
			// shift pointer to next color
			pColor += Bpp;
			// place part of scan line as RECT region if transparent color found after mask color or
			// mask color found at the end of mask image
			if ( wasfirst )
			{
				if ( !ismask )
				{
					// save current RECT
					pRects[ pRgnData->nCount++ ] = CRect( first, i, j, i + 1 );
					// if buffer full reallocate it with more room
					if ( pRgnData->nCount >= dwRectsCount )
					{
						dwRectsCount += ADD_RECTS_COUNT;
						// allocate new buffer
						LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
						// copy current region data to it
						memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
						// delte old region data buffer
						delete pRgnData;
						// set pointer to new regiondata buffer to current
						pRgnData = (RGNDATAHEADER*)pRgnDataNew;
						// correct pointer to RECT table
						pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
					}
					wasfirst = false;
				}
			}
			else if ( ismask )		// set wasfirst when mask is found
			{
				first = j;
				wasfirst = true;
			}
		}

		if ( wasfirst && ismask )
		{
			// save current RECT
			pRects[ pRgnData->nCount++ ] = CRect( first, i, j, i + 1 );
			// if buffer full reallocate it with more room
			if ( pRgnData->nCount >= dwRectsCount )
			{
				dwRectsCount += ADD_RECTS_COUNT;
				// allocate new buffer
				LPBYTE pRgnDataNew = new BYTE[ RGNDATAHEADER_SIZE + dwRectsCount * sizeof(RECT) ];
				// copy current region data to it
				memcpy( pRgnDataNew, pRgnData, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT) );
				// delte old region data buffer
				delete [] pRgnData;
				// set pointer to new regiondata buffer to current
				pRgnData = (RGNDATAHEADER*)pRgnDataNew;
				// correct pointer to RECT table
				pRects = (LPRECT)((LPBYTE)pRgnData + RGNDATAHEADER_SIZE);
			}
			wasfirst = false;
		}

		pColor -= dwLineBackLen;
	}
	// release image data
	delete [] pBits;
	delete [] bi;

	// create region
	HRGN hRgn = ExtCreateRegion( NULL, RGNDATAHEADER_SIZE + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData );
	// release region data
	delete [] pRgnData;

	return hRgn;
}
void CSkinBitmap::ModifyHue(CDC *pDC,int nWidth,int nHeight,int nPercent)
{
	double    H, L, S ;
	COLORREF color ;
	for(int i = 0 ; i < nWidth ; i++)
		for(int j = 0 ; j < nHeight ; j++)
		{
			color = pDC->GetPixel(i,j);
			RGBtoHLS(color,&H,&L,&S);
			if (nPercent != 100)
				H = H * nPercent / 100 ;
			color = HLStoRGB(H,L,S);
			pDC->SetPixel(i,j,color);
		}
}
void CSkinBitmap::ModifyHue(int nPercent)
{
	DeleteObject();
	LoadImage(m_lpBuffer,m_nSize);
	HDC dc = CreateIC( _TEXT("DISPLAY"),NULL,NULL,NULL );
	CDC *pDC = CDC::FromHandle(dc);
	CCompatibleDC memDC(pDC,this);
	int nWidth = GetWidth();
	int nHeight = GetHeight();
	
	ModifyHue(&memDC,nWidth,nHeight, nPercent);

	DeleteDC(dc);
}
BOOL CSkinBitmap::Copy(const CSkinBitmap *pSrc) 
{
	if(pSrc == NULL)
		return FALSE;
	if(m_lpBuffer)
		delete []m_lpBuffer;
	m_strName = pSrc->m_strName;
	m_nSize = pSrc->m_nSize;
	m_lpBuffer = new BYTE[m_nSize];
	if(!m_lpBuffer)
		return FALSE;
	::CopyMemory(m_lpBuffer,pSrc->m_lpBuffer,m_nSize);
	LoadImage(m_lpBuffer,m_nSize);
	return TRUE;
}